﻿using System;

using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Silvermoon.Controls;

namespace Silvermoon.Windows
{
    // Creates a weak event handler which allows both sender and listener to be garbage collected.
    public class WeakSparseEventListener
    {
        private WeakReference sender;
        private WeakReference listener;
        private EventHandler action;
        private SparseEvent sparseEvent;

        /// <summary>
        /// Creates a new weak event which decouples sender and listener hence alowing both sender and receiver to be garbage collected while
        ///  the event is still connected.
        /// </summary>
        /// <param name="control">Control for which add the weak event.</param>
        /// <param name="sparseEvent">SparseEvent to add.</param>
        /// <param name="target">Target which receivces events.</param>
        /// <param name="action">Action to perform when the event occurs. IMPORTANT: this must be a static method!</param>
        public WeakSparseEventListener(Control control, SparseEvent sparseEvent, object target, EventHandler action)
        {
            this.sparseEvent = sparseEvent;
            this.sender = new WeakReference(sender);
            this.listener = new WeakReference(target);
            this.action = action;
            Delegate d = new EventHandler(OnEvent);
            control.AddHandler(sparseEvent, d);
        }

        ~WeakSparseEventListener()
        {
            Disconnect();
            if (listener != null) listener.Target = null;
            if (sender != null) sender.Target = null;
        }

        private void OnEvent(object s, EventArgs e)
        {
            if (listener!=null && !listener.IsAlive)
            {
                Disconnect();
            }
            else
            {
                action(listener.Target, e);
            }
        }

        public void Disconnect()
        {
            if (sender != null && sender.Target != null)
            {
                if (sender.IsAlive) ((Control)sender.Target).RemoveHandler(sparseEvent, (EventHandler)OnEvent);
                listener.Target = null;
                sender.Target = null;
            }
        }
    }
}
